package com.yowasa.xiuxian.engine.travel;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.yowasa.xiuxian.engine.BattleEngine;
import com.yowasa.xiuxian.entity.bo.battle.BattleContent;
import com.yowasa.xiuxian.entity.bo.enemy.BossBO;
import com.yowasa.xiuxian.entity.bo.enemy.EnemyBO;
import com.yowasa.xiuxian.entity.bo.enemy.EnemyDropBO;
import com.yowasa.xiuxian.entity.bo.user.UserBO;
import com.yowasa.xiuxian.entity.enums.MapEnum;
import com.yowasa.xiuxian.entity.enums.RefreshType;
import com.yowasa.xiuxian.service.helper.*;
import com.yowasa.xiuxian.util.RandomUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.text.MessageFormat;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

@Slf4j
@Component
public class YeWaiTravel implements TravelInterface {
    @Autowired
    private UserHelper userHelper;
    @Autowired
    private EnemyHelper enemyHelper;
    @Autowired
    private BattleEngine battleEngine;
    @Autowired
    private BattleHelper battleHelper;
    @Autowired
    private ItemHelper itemHelper;
    @Autowired
    private ResourceHelper resourceHelper;
    @Value("${xiuxian.rate.boss}")
    private int bossRate;

    @Override
    public int getType() {
        return 3;
    }


    @Override
    public String exec(UserBO userBO) {
        MapEnum mapEnum = MapEnum.getById(userBO.getLocal());
        String bossTag = "BOSS_" + mapEnum.getName();
        //检查地图是否有boss
        if (resourceHelper.checkHaveResource(userBO.getGuildId(), bossTag, RefreshType.ENTITY)) {
            BossBO entity = resourceHelper.getEntity(userBO.getGuildId(), bossTag, BossBO.class);
            String msg = "你前往讨伐boss" + "\n" + bossBattle(userBO, entity);
            resourceHelper.refreshEntity(userBO.getGuildId(), bossTag, entity);
            if (entity.getEnemyBO().getUserBO().getUserBattle().getChp() <= 0) {
                resourceHelper.useResource(userBO.getGuildId(), bossTag);
            }
            return msg;
        } else {
            if (enemyHelper.checkHaveBoss(mapEnum)) {
                if (RandomUtil.randomInt(1, 100) <= bossRate) {
                    EnemyBO enemyBO = enemyHelper.genEnemy(mapEnum, 1);
                    BossBO entity = new BossBO();
                    entity.setDiscoverAccountId(userBO.getId());
                    entity.setEnemyBO(enemyBO);
                    String msg = "你游历时" + entity.getEnemyBO().getMsg() + "\n" + bossBattle(userBO, entity);
                    resourceHelper.refreshEntity(userBO.getGuildId(), bossTag, entity);
                    if (entity.getEnemyBO().getUserBO().getUserBattle().getChp() <= 0) {
                        resourceHelper.useResource(userBO.getGuildId(), bossTag);
                    }
                    return msg;
                }
            }
        }
        return normalBattle(userBO);
    }

    private String bossBattle(UserBO userBO, BossBO entity) {
        EnemyBO enemyBO = entity.getEnemyBO();
        UserBO enemy = enemyBO.getUserBO();
        int beforeChp = enemy.getUserBattle().getChp();
        //执行战斗
        BattleContent content = battleEngine.battle(userBO, enemy);
        battleEngine.duelSouHun(content);
        int days = battleHelper.calCostTime(content) + RandomUtil.randomInt(10, 30);
        //同步血量
        battleHelper.syncUserState(content);
        //记录伤害
        int reduceHp = beforeChp - enemy.getUserBattle().getChp();
        entity.getDamageMap().put(userBO.getId(), entity.getDamageMap().getOrDefault(userBO.getId(), 0) + reduceHp);
        userHelper.lockUser(userBO, days, userBO.getName() + "正在BOSS战");
        EnemyDropBO dropBO = enemyBO.getDropBO();
        int getTravel = dropBO.getTravel();
        String msg = content.getMsgLog().stream().collect(Collectors.joining("\n"));
        if (content.getSecond().getBattleInfo().getChp() > 0) {
            getTravel = getTravel * content.getTurn() * userBO.getUserAttr().getUnd() / (20 * 50);
            getTravel = RandomUtil.waveInt(getTravel, 30);
            userBO.getUserConfig().setTravel(userBO.getUserConfig().getTravel() + getTravel);
            return MessageFormat.format("{0}\n一番战斗后你被打得落荒而逃\n消耗{1}天,获取了{2}点历练值,你对boss共计造成了{3}点伤害", msg, days, getTravel, reduceHp);
        }
        //越级击杀
        if (userBO.getStage() - enemy.getStage() > 4) {
            getTravel = getTravel / 10;
            userBO.getUserConfig().setTravel(userBO.getUserConfig().getTravel() + getTravel);
            return MessageFormat.format("{0}\n你以压倒性的实力将其灰飞烟灭\n消耗{1}天,获取了{2}点历练值", msg, days, getTravel);
        }
        getTravel = RandomUtil.waveInt(getTravel, 30);
        userBO.getUserConfig().setTravel(userBO.getUserConfig().getTravel() + getTravel);
        //分配金币
        Map<UserBO, Integer> allocateGoldMap = allocateGold(userBO, entity);

        //分配道具
        Map<String, Integer> itemGet = getItems(userBO, dropBO);
        Map<UserBO, Map<String, Integer>> userBOMapMap = allocateItem(allocateGoldMap.keySet(), itemGet);

        String gainMsg = allocateGoldMap.keySet().stream().map(e -> {
            Map<String, Integer> getItems = null;
            for (Map.Entry<UserBO, Map<String, Integer>> entry : userBOMapMap.entrySet()) {
                if (e.getId().equals(entry.getKey().getId())) {
                    getItems = entry.getValue();
                    break;
                }
            }
            Integer gold = 0;
            for (Map.Entry<UserBO, Integer> entry : allocateGoldMap.entrySet()) {
                if (e.getId().equals(entry.getKey().getId())) {
                    gold = entry.getValue();
                    break;
                }
            }
            String exMsg = "";
            if (getItems != null) {
                exMsg = "," + getItemGetMsg(getItems);
            }
            return MessageFormat.format("{0}获取了{1}摩拉{2}", e.getName(), gold, exMsg);
        }).collect(Collectors.joining("\n"));
        return MessageFormat.format("{0}\n一番战斗后你取得了胜利\n消耗{1}天,获取了{2}点历练值\n分配掉落如下:\n{3}", msg, days, getTravel, gainMsg);

    }

    //分配道具
    private Map<UserBO, Map<String, Integer>> allocateItem(Set<UserBO> userBOSet, Map<String, Integer> itemGet) {
        List<UserBO> userBOS = Lists.newArrayList(userBOSet);
        Map<UserBO, Map<String, Integer>> result = Maps.newHashMap();
        for (Map.Entry<String, Integer> entry : itemGet.entrySet()) {
            for (Integer i = 0; i < entry.getValue(); i++) {
                UserBO choice = RandomUtil.choice(userBOS);
                Map<String, Integer> eachGetItemMap = result.getOrDefault(choice, Maps.newHashMap());
                eachGetItemMap.put(entry.getKey(), eachGetItemMap.getOrDefault(entry.getKey(), 0) + 1);
                result.put(choice, eachGetItemMap);
            }
        }
        for (Map.Entry<UserBO, Map<String, Integer>> userBOMapEntry : result.entrySet()) {
            itemHelper.addItems(userBOMapEntry.getKey(), userBOMapEntry.getValue());
        }
        return result;
    }

    //分配金币
    private Map<UserBO, Integer> allocateGold(UserBO userBO, BossBO entity) {
        //获取分的钱列表
        int total = entity.getEnemyBO().getDropBO().getGold();
        Map<Long, Integer> damageMap = entity.getDamageMap();
        Set<Long> topKey = RandomUtil.getTopKey(damageMap, 3);
        int split = 2 + topKey.size();
        List<Integer> eachList = RandomUtil.intSplit(total, 1, split);
        //获取分钱人员
        Set<Long> accIdSet = Sets.newHashSet(userBO.getId(), entity.getDiscoverAccountId());
        accIdSet.addAll(topKey);
        Map<Long, UserBO> userBOMap = Maps.newHashMap();
        for (Long accId : accIdSet) {
            if (userBO.getId().equals(accId)) {
                userBOMap.put(accId, userBO);
            } else {
                UserBO byId = userHelper.getById(accId);
                if (byId != null) {
                    userBOMap.put(accId, byId);
                }
            }
        }
        //开始分配
        Map<UserBO, Integer> allocateMap = Maps.newHashMap();

        //击杀者
        allocateMap.put(userBO, eachList.get(0));
        //发现者
        UserBO discover = userBOMap.get(entity.getDiscoverAccountId());
        if (discover != null) {
            allocateMap.put(discover, allocateMap.getOrDefault(discover, 0) + eachList.get(1));
        }
        int n = 1;
        for (Long key : topKey) {
            n += 1;
            UserBO eu = userBOMap.get(key);
            if (eu != null) {
                allocateMap.put(eu, allocateMap.getOrDefault(eu, 0) + eachList.get(n));
            }
        }
        //保存（除击杀者外）
        for (UserBO value : userBOMap.values()) {
            value.getUserConfig().setGold(value.getUserConfig().getGold() + allocateMap.getOrDefault(value, 0));
            if (value != userBO) {
                userHelper.saveUserInfo(value);
            }
        }
        return allocateMap;
    }


    public String normalBattle(UserBO userBO) {
        MapEnum mapEnum = MapEnum.getById(userBO.getLocal());
        //构建怪物对象
        EnemyBO enemyBO = enemyHelper.genEnemy(mapEnum, 0);
        UserBO enemy = enemyBO.getUserBO();
        //战斗
        BattleContent content = battleEngine.battle(userBO, enemy);
        //搜魂大法处理
        battleEngine.duelSouHun(content);
        int baseDays = RandomUtil.randomInt(10, 30);
        int days = battleHelper.calCostTime(content);
        battleHelper.syncUserState(content);
        userHelper.lockUser(userBO, baseDays + days, userBO.getName() + "正在历练中");
        EnemyDropBO dropBO = enemyBO.getDropBO();
        String prefix;
        String end = "";
        int getTravel = dropBO.getTravel();
        if (content.getResult() == 1) {
            prefix = "一番战斗后你取得了胜利";
            if (userBO.getStage() - enemy.getStage() > 2) {
                end = ",你以压倒性的实力将其灰飞烟灭";
                getTravel = getTravel / 10;
            } else {
                int getGold = dropBO.getGold();
                if (getGold > 0) {
                    getGold = RandomUtil.waveInt(getGold, 20);
                    userBO.getUserConfig().setGold(userBO.getUserConfig().getGold() + getGold);
                    end = ",一番搜刮后获取了" + getGold + "摩拉";
                }
            }
            Map<String, Integer> itemGet = getItems(userBO, dropBO);
            if (!itemGet.isEmpty()) {
                end += ",";
                if (StringUtils.isEmpty(end)) {
                    end += "一番搜刮后获取了";
                }
                end += getItemGetMsg(itemGet);
            }
            log.info("获取的物品：{}", itemGet);
            itemHelper.addItems(userBO, itemGet);

        } else {
            prefix = "一番战斗后你被打得落荒而逃";
            getTravel = getTravel * content.getTurn() * userBO.getUserAttr().getUnd() / (20 * 50);
        }
        getTravel = RandomUtil.waveInt(getTravel, 30);
        userBO.getUserConfig().setTravel(userBO.getUserConfig().getTravel() + getTravel);
        String msg = content.getMsgLog().stream().collect(Collectors.joining("\n"));
        return MessageFormat.format("你游历的第{6}天{0}\n{1}\n消耗{2}天,{3},获取了{4}点历练值{5}", enemyBO.getMsg(), msg, days, prefix, getTravel, end, baseDays);
    }


    private Map<String, Integer> getItems(UserBO userBO, EnemyDropBO dropBO) {
        Map<String, Integer> itemGet = Maps.newHashMap();
        //获取物品
        for (Map.Entry<String, Integer> entry : dropBO.getItemMap().entrySet()) {
            int num = 0;
            int i = RandomUtil.randomInt(100);
            Integer value = entry.getValue();
            int luc = userBO.getUserAttr().getLuc();
            int getRate = value * luc / 50;
            num += getRate / 100;
            getRate = getRate % 100;
            if (i <= getRate) {
                num += 1;
            }
            if (num > 0) {
                itemGet.put(entry.getKey(), num);
            }
        }
        return itemGet;
    }

    /**
     * 获取物品列表的描述
     *
     * @param itemGet
     * @return
     */
    private String getItemGetMsg(Map<String, Integer> itemGet) {
        List<String> itemMsg = Lists.newArrayList();
        for (Map.Entry<String, Integer> entry : itemGet.entrySet()) {
            itemMsg.add(MessageFormat.format("[{0}]*{1}", entry.getKey(), entry.getValue()));
        }
        return itemMsg.stream().collect(Collectors.joining(","));
    }


}
